package com.hongliang.lock;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Hongliang Zhu
 * @create 2022-02-27 19:50
 */
public class SynchronizedByKey {
    Map<String, ReentrantLock> mutexCache = new ConcurrentHashMap<>();

    public void exec(String key, Runnable command) {
        ReentrantLock mutexKey = mutexCache.computeIfAbsent(key, k -> new ReentrantLock());
        mutexKey.lock();
        try {
            command.run();
        } finally {
            if (mutexKey.getQueueLength() == 0) {
                // todo 在移除锁对象之前，这时候的线程进来，拿到被remove的锁，后续进程再次进来就需要重新创建锁，导致两个线程并发执行。
                mutexCache.remove(key);
            }
            mutexKey.unlock();
        }
    }


    public void execSync(String key, Runnable command) {
        ReentrantLock mutexKey = null;
        ReentrantLock mutexInCache = null;
        do {
            if (mutexKey != null) {
                mutexKey.unlock();
            }
            mutexKey = mutexCache.computeIfAbsent(key, k -> new ReentrantLock());
            mutexKey.lock();
            mutexInCache = mutexCache.get(key);
        } while (mutexInCache != mutexKey);

        try {
            command.run();
        } finally {
            if (mutexKey.getQueueLength() == 0) {
                // todo 在移除锁对象之前，这时候的线程进来，拿到被remove的锁，后续进程再次进来就需要重新创建锁，导致两个线程并发执行。
                mutexCache.remove(key);
            }
            mutexKey.unlock();
        }

    }

}
